package crudfx.util;

import javax.swing.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.io.*;
import java.util.*;

import javax.swing.plaf.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.text.html.*;
import javax.accessibility.*;
/**
 * @profile desktop
 * @author Sergey Surikov
 */
/*
class SEditorKit extends HTMLEditorKit {

public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {

if (doc instanceof HTMLDocument) {
HTMLDocument hdoc = (HTMLDocument) doc;
Parser p = getParser();
if (p == null) {
throw new IOException("Can't load parser");
}
if (pos > doc.getLength()) {
throw new BadLocationException("Invalid location", pos);
}

ParserCallback receiver = hdoc.getReader(pos);
Boolean ignoreCharset = (Boolean) doc.getProperty("IgnoreCharsetDirective");
p.parse(in, receiver, (ignoreCharset == null) ? false : ignoreCharset.booleanValue());
receiver.flush();
} else {
super.read(in, doc, pos);
}
}
}*/

public class SEditorPane extends JEditorPane {

    HTMLEditorKit editorKit = new HTMLEditorKit();
    boolean isSetPage = false;
    //final static String PostDataProperty = "javax.swing.JEditorPane.postdata";
    //private Hashtable pageProperties;

    public SEditorPane() {
        this.setEditable(false);
        this.setEditorKit(editorKit);
    //System.out.println("start---------------\n\n\n--------------------");
    //this.setE
    //kit = new HTMLEditorKit();
    //jEditorPane = new JEditorPane();
    //this.setUI(jEditorPane.getUI());
    }

    private Document initializeModel(EditorKit kit, URL page) {
        Document doc = kit.createDefaultDocument();
        /*if (pageProperties != null) {
        // transfer properties discovered in stream to the
        // document property collection.
        for (Enumeration e = pageProperties.keys(); e.hasMoreElements();) {
        Object key = e.nextElement();
        doc.putProperty(key, pageProperties.get(key));
        }
        pageProperties.clear();
        }*/
        if (doc.getProperty(Document.StreamDescriptionProperty) == null) {
            doc.putProperty(Document.StreamDescriptionProperty, page);
        }
        return doc;
    }

    public void setDocument(Document doc) {
        if (!isSetPage) {
            super.setDocument(doc);
        }
    }

    public void setPage(URL page) throws IOException {
        isSetPage = true;
        URL loaded = getPage();
        InputStream in = getStream(page);
        Document doc = initializeModel(editorKit, page);
        read(in, doc);
        setDocument(doc);
    /*final String reference = page.getRef();
    scrollToReference(reference);
    getDocument().putProperty(Document.StreamDescriptionProperty, page);
    firePropertyChange("page", loaded, page);*/
    }

    void read(InputStream in, Document doc) throws IOException {
        if (!Boolean.TRUE.equals(doc.getProperty("IgnoreCharsetDirective"))) {
            final int READ_LIMIT = 1024 * 10;
            in = new BufferedInputStream(in, READ_LIMIT);
            in.mark(READ_LIMIT);
        }
        try {
            String charset = (String) getClientProperty("charset");
            Reader r = (charset != null) ? new InputStreamReader(in, charset) : new InputStreamReader(in);
            editorKit.read(r, doc, 0);
        } catch (BadLocationException e) {
            throw new IOException(e.getMessage());
        } catch (ChangedCharSetException changedCharSetException) {
            String charSetSpec = changedCharSetException.getCharSetSpec();
            if (changedCharSetException.keyEqualsCharSet()) {
                putClientProperty("charset", charSetSpec);
            } else {
                setCharsetFromContentTypeParameters(charSetSpec);
            }
            try {
                in.reset();
            } catch (IOException exception) {
                //mark was invalidated
                in.close();
                URL url = (URL) doc.getProperty(Document.StreamDescriptionProperty);
                if (url != null) {
                    URLConnection conn = url.openConnection();
                    in = conn.getInputStream();
                } else {
                    //there is nothing we can do to recover stream
                    throw changedCharSetException;
                }
            }
            try {
                doc.remove(0, doc.getLength());
            } catch (BadLocationException e) {
            }
            doc.putProperty("IgnoreCharsetDirective", Boolean.valueOf(true));
            read(in, doc);
        }
    }

    private void setCharsetFromContentTypeParameters(String paramlist) {
        String charset = null;
        try {
            // paramlist is handed to us with a leading ';', strip it.
            int semi = paramlist.indexOf(';');
            if (semi > -1 && semi < paramlist.length() - 1) {
                paramlist = paramlist.substring(semi + 1);
            }

            if (paramlist.length() > 0) {
                // parse the paramlist into attr-value pairs & get the
                // charset pair's value
                HeaderParser hdrParser = new HeaderParser(paramlist);
                charset = hdrParser.findValue("charset");
                if (charset != null) {
                    putClientProperty("charset", charset);
                }
            }
        } catch (IndexOutOfBoundsException e) {
            // malformed parameter list, use charset we have
        } catch (NullPointerException e) {
            // malformed parameter list, use charset we have
        } catch (Exception e) {
            // malformed parameter list, use charset we have; but complain
            System.err.println("JEditorPane.getCharsetFromContentTypeParameters failed on: " + paramlist);
            e.printStackTrace();
        }
    }

    static class HeaderParser {

        /* table of key/val pairs - maxes out at 10!!!!*/
        String raw;
        String[][] tab;

        public HeaderParser(String raw) {
            this.raw = raw;
            tab = new String[10][2];
            parse();
        }

        private void parse() {

            if (raw != null) {
                raw = raw.trim();
                char[] ca = raw.toCharArray();
                int beg = 0, end = 0, i = 0;
                boolean inKey = true;
                boolean inQuote = false;
                int len = ca.length;
                while (end < len) {
                    char c = ca[end];
                    if (c == '=') { // end of a key
                        tab[i][0] = new String(ca, beg, end - beg).toLowerCase();
                        inKey = false;
                        end++;
                        beg = end;
                    } else if (c == '\"') {
                        if (inQuote) {
                            tab[i++][1] = new String(ca, beg, end - beg);
                            inQuote = false;
                            do {
                                end++;
                            } while (end < len && (ca[end] == ' ' || ca[end] == ','));
                            inKey = true;
                            beg = end;
                        } else {
                            inQuote = true;
                            end++;
                            beg = end;
                        }
                    } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
                        if (inQuote) {
                            end++;
                            continue;
                        } else if (inKey) {
                            tab[i++][0] = (new String(ca, beg, end - beg)).toLowerCase();
                        } else {
                            tab[i++][1] = (new String(ca, beg, end - beg));
                        }
                        while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
                            end++;
                        }
                        inKey = true;
                        beg = end;
                    } else {
                        end++;
                    }
                }
                // get last key/val, if any
                if (--end > beg) {
                    if (!inKey) {
                        if (ca[end] == '\"') {
                            tab[i++][1] = (new String(ca, beg, end - beg));
                        } else {
                            tab[i++][1] = (new String(ca, beg, end - beg + 1));
                        }
                    } else {
                        tab[i][0] = (new String(ca, beg, end - beg + 1)).toLowerCase();
                    }
                } else if (end == beg) {
                    if (!inKey) {
                        if (ca[end] == '\"') {
                            tab[i++][1] = String.valueOf(ca[end - 1]);
                        } else {
                            tab[i++][1] = String.valueOf(ca[end]);
                        }
                    } else {
                        tab[i][0] = String.valueOf(ca[end]).toLowerCase();
                    }
                }
            }

        }

        public String findKey(int i) {
            if (i < 0 || i > 10) {
                return null;
            }
            return tab[i][0];
        }

        public String findValue(int i) {
            if (i < 0 || i > 10) {
                return null;
            }
            return tab[i][1];
        }

        public String findValue(String key) {
            return findValue(key, null);
        }

        public String findValue(String k, String Default) {
            if (k == null) {
                return Default;
            }
            k = k.toLowerCase();
            for (int i = 0; i < 10; ++i) {
                if (tab[i][0] == null) {
                    return Default;
                } else if (k.equals(tab[i][0])) {
                    return tab[i][1];
                }
            }
            return Default;
        }

        public int findInt(String k, int Default) {
            try {
                return Integer.parseInt(findValue(k, String.valueOf(Default)));
            } catch (Throwable t) {
                return Default;
            }
        }
    }
}
